﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Dynamic;
using System.Linq;
using Mefisto.Core.Caching.Contracts;
using Mefisto.Core.Extensions;
using Mefisto.Core.Resources.Contracts;

namespace Mefisto.Modules.Default.Resource
{
    [Export(typeof(IResourceProvider))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class DefaultResourceProvider : IResourceProvider
    {
        #region ImportedFields

        /// <summary>
        /// Provider permettant de gérer le cache
        /// </summary>
        [Import]
        public ICacheProvider CacheProvider;

        #endregion

        #region Fields

        protected object _lock = new object();

        private ExpandoObject _translationBag;

        #endregion

        #region Properties

        /// <summary>
        /// Variable dynamique permettant de passer des paramètres nommés aux méthodes de récupération des ressources
        /// </summary>
        public dynamic TranslationBag
        {
            get { return _translationBag ?? (_translationBag = new ExpandoObject()); }
            set { _translationBag = value; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Method for getting resource translation
        /// </summary>
        /// <param name="resourceCode">Resource code</param>
        /// <param name="cultureCode">Culture code (Optional)</param>
        /// <param name="applicationCode">Application code (Optional)</param>
        /// <returns>Resource translation</returns>
        public string GetTranslation(string resourceCode, string cultureCode = "", string applicationCode = "")
        {
            lock (_lock)
            {
                string resource;

                //Si possible, on récupère la ressource depuis le cache
                if (!CacheProvider.Get<string>(out resource, "Resources", resourceCode, cultureCode, applicationCode))
                {
                    //Si la ressource n'existe pas dans le cache, on la récupère depuis la base de données, et on la met en cache
                    RetrieveResources(resourceCode, cultureCode, applicationCode);
                    //Si la ressource n'existe toujours pas dans le cache, alors on renvoie une valeur par défaut
                    if (!CacheProvider.Get<string>(out resource, "Resources", resourceCode, cultureCode, applicationCode))
                        return "#" + resourceCode;
                }

                //On injecte les paramètres au niveau de la ressource avant de la retourner
                var resourceParams = TranslationBag as IDictionary<string, object>;
                return resourceParams == null ? resource.InjectParameters(@"[=([\w.]+)]", "[={0}]") : resource.InjectParameters(@"[=([\w.]+)]", "[={0}]", resourceParams.Select(r => new KeyValuePair<string, object>(r.Key, r.Value)).ToArray());
            }
        }

        /// <summary>
        /// Method for getting all resource codes
        /// </summary>
        /// <param name="cultureCode">Culture code (Optional)</param>
        /// <param name="applicationCode">Application code (Optional)</param>
        /// <returns></returns>
        public IEnumerable<string> GetAllResourceCodes(string cultureCode = "", string applicationCode = "")
        {
            // TODO
            throw new NotImplementedException();
        }

        /// <summary>
        /// Method for deleting translations
        /// </summary>
        /// <param name="cultureCode">Culture code (Optional)</param>
        /// <param name="applicationCode">Application code (Optional)</param>
        public void ClearTranslations(string cultureCode = "", string applicationCode = "")
        {
            lock (_lock)
            {
                CacheProvider.Clear("Resources");
            }
        }

        /// <summary>
        /// Method for clearing the translation bag
        /// </summary>
        public void ClearTranslationBag()
        {
            _translationBag = new ExpandoObject();
        }

        /// <summary>
        /// Method for getting available cultures list
        /// </summary>
        /// <param name="applicationCode">Application code (Optional)</param>
        /// <returns>Cultures Dictionary (Code/Name)</returns>
        public IDictionary<string, string> GetAvailableCultures(string applicationCode = "")
        {
            lock (_lock)
            {
                var cultures = new Dictionary<string, string>();

                // TODO

                ////Si possible, on récupère les cultures depuis le cache
                //if (!CacheProvider.Get<Dictionary<string, string>>(out cultures, "AvailableCultures", applicationCode))
                //{
                //    //Si la ressource n'existe pas dans le cache, on la récupère depuis la base de données, et on la met en cache
                //    //On mutualise la récupération des ressources par page de 50
                //    using (var provider = PortalHelper.GetProvider<AbstractStarfleetProvider>())
                //    {
                //        cultures = provider.GetSimpleLanguages(applicationCode).ToDictionary<SimpleLanguage, string, string>(l => l.LanguageCulture, l => l.LanguageName);
                //    }

                //    CacheProvider.Set<Dictionary<string, string>>(cultures, "AvailableCultures", applicationCode);
                //}

                return cultures;
            }
        }

        #endregion

        #region Internal Methods

        protected void RetrieveResources(string resourceCode, string cultureCode, string applicationCode)
        {
            lock (_lock)
            {
                // TODO

                //var resources = new List<ComplexResource>();

                ////On mutualise la récupération des ressources par page de 50
                //using (var provider = PortalHelper.GetProvider<AbstractStarfleetProvider>())
                //{
                //    resources = provider.GetComplexResources(cultureCode, applicationCode, resourceCode, 50).ToList();
                //}

                //foreach (var resource in resources)
                //{
                //    CacheProvider.Set<string>(resource.ResourceSentence, "Resources", resource.ResourceCode, cultureCode, applicationCode);
                //}
            }
        }

        #endregion
    }
}